<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="../Styles/sure3.css" rel="stylesheet" type="text/css"/>
    <link href="../Styles/base1.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div class="markdown-body entry-content" itemprop="text">
    <h1><a href="#reflect"  class="anchor" id="user-content-reflect">

    </a>Reflect
    </h1>
    <h2><a href="#概述"  class="anchor" id="user-content-概述">

    </a>概述
    </h2>
    <p><code>Reflect</code>对象与<code>Proxy</code>对象一样，也是 ES6 为了操作对象而提供的新 API。<code>Reflect</code>对象的设计目的有这样几个。</p>
    <p>（1） 将<code>Object</code>对象的一些明显属于语言内部的方法（比如<code>Object.defineProperty</code>），放到<code>Reflect</code>对象上。现阶段，某些方法同时在<code>Object</code>和<code>Reflect</code>对象上部署，未来的新方法将只部署在<code>Reflect</code>对象上。也就是说，从<code>Reflect</code>对象上可以拿到语言内部的方法。
    </p>
    <p>（2） 修改某些<code>Object</code>方法的返回结果，让其变得更合理。比如，<code>Object.defineProperty(obj, name, desc)</code>在无法定义属性时，会抛出一个错误，而<code>Reflect.defineProperty(obj,
        name, desc)</code>则会返回<code>false</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 老写法</span>
<span class="pl-k">try</span> {
  <span class="pl-c1">Object</span>.<span class="pl-en">defineProperty</span>(target, property, attributes);
  <span class="pl-c"><span class="pl-c">//</span> success</span>
} <span class="pl-k">catch</span> (e) {
  <span class="pl-c"><span class="pl-c">//</span> failure</span>
}

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-k">if</span> (<span class="pl-c1">Reflect</span>.<span class="pl-en">defineProperty</span>(target, property, attributes)) {
  <span class="pl-c"><span class="pl-c">//</span> success</span>
} <span class="pl-k">else</span> {
  <span class="pl-c"><span class="pl-c">//</span> failure</span>
}</pre>
    </div>
    <p>（3） 让<code>Object</code>操作都变成函数行为。某些<code>Object</code>操作是命令式，比如<code>name in obj</code>和<code>delete
        obj[name]</code>，而<code>Reflect.has(obj, name)</code>和<code>Reflect.deleteProperty(obj, name)</code>让它们变成了函数行为。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 老写法</span>
<span class="pl-s"><span class="pl-pds">'</span>assign<span class="pl-pds">'</span></span> <span class="pl-k">in</span> <span
                class="pl-c1">Object</span> <span class="pl-c"><span class="pl-c">//</span> true</span>

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-c1">has</span>(<span class="pl-c1">Object</span>, <span class="pl-s"><span
                class="pl-pds">'</span>assign<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> true</span></pre>
    </div>
    <p>（4）<code>Reflect</code>对象的方法与<code>Proxy</code>对象的方法一一对应，只要是<code>Proxy</code>对象的方法，就能在<code>Reflect</code>对象上找到对应的方法。这就让<code>Proxy</code>对象可以方便地调用对应的<code>Reflect</code>方法，完成默认行为，作为修改行为的基础。也就是说，不管<code>Proxy</code>怎么修改默认行为，你总可以在<code>Reflect</code>上获取默认行为。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">Proxy</span>(target, {
  <span class="pl-en">set</span><span class="pl-k">:</span> <span class="pl-k">function</span>(<span class="pl-smi">target</span>, <span
                class="pl-smi">name</span>, <span class="pl-smi">value</span>, <span class="pl-smi">receiver</span>) {
    <span class="pl-k">var</span> success <span class="pl-k">=</span> <span class="pl-c1">Reflect</span>.<span
                class="pl-c1">set</span>(target,name, value, receiver);
    <span class="pl-k">if</span> (success) {
      <span class="pl-en">log</span>(<span class="pl-s"><span class="pl-pds">'</span>property <span
                class="pl-pds">'</span></span> <span class="pl-k">+</span> name <span class="pl-k">+</span> <span
                class="pl-s"><span class="pl-pds">'</span> on <span class="pl-pds">'</span></span> <span
                class="pl-k">+</span> target <span class="pl-k">+</span> <span class="pl-s"><span
                class="pl-pds">'</span> set to <span class="pl-pds">'</span></span> <span class="pl-k">+</span> value);
    }
    <span class="pl-k">return</span> success;
  }
});</pre>
    </div>
    <p>上面代码中，<code>Proxy</code>方法拦截<code>target</code>对象的属性赋值行为。它采用<code>Reflect.set</code>方法将值赋值给对象的属性，确保完成原有的行为，然后再部署额外的功能。
    </p>
    <p>下面是另一个例子。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> loggedObj <span class="pl-k">=</span> <span
            class="pl-k">new</span> <span class="pl-en">Proxy</span>(obj, {
  <span class="pl-en">get</span>(<span class="pl-smi">target</span>, <span class="pl-smi">name</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>get<span
                class="pl-pds">'</span></span>, target, name);
    <span class="pl-k">return</span> <span class="pl-c1">Reflect</span>.<span class="pl-c1">get</span>(target, name);
  },
  <span class="pl-en">deleteProperty</span>(<span class="pl-smi">target</span>, <span class="pl-smi">name</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>delete<span
                class="pl-pds">'</span></span> <span class="pl-k">+</span> name);
    <span class="pl-k">return</span> <span class="pl-c1">Reflect</span>.<span class="pl-en">deleteProperty</span>(target, name);
  },
  <span class="pl-en">has</span>(<span class="pl-smi">target</span>, <span class="pl-smi">name</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>has<span
                class="pl-pds">'</span></span> <span class="pl-k">+</span> name);
    <span class="pl-k">return</span> <span class="pl-c1">Reflect</span>.<span class="pl-c1">has</span>(target, name);
  }
});</pre>
    </div>
    <p>
        上面代码中，每一个<code>Proxy</code>对象的拦截操作（<code>get</code>、<code>delete</code>、<code>has</code>），内部都调用对应的<code>Reflect</code>方法，保证原生行为能够正常执行。添加的工作，就是将每一个操作输出一行日志。
    </p>
    <p>有了<code>Reflect</code>对象以后，很多操作会更易读。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 老写法</span>
<span class="pl-c1">Function</span>.<span class="pl-c1">prototype</span>.<span class="pl-smi">apply</span>.<span
                class="pl-c1">call</span>(<span class="pl-c1">Math</span>.<span class="pl-smi">floor</span>, <span
                class="pl-c1">undefined</span>, [<span class="pl-c1">1.75</span>]) <span class="pl-c"><span
                class="pl-c">//</span> 1</span>

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-c1">apply</span>(<span class="pl-c1">Math</span>.<span
                class="pl-smi">floor</span>, <span class="pl-c1">undefined</span>, [<span
                class="pl-c1">1.75</span>]) <span class="pl-c"><span class="pl-c">//</span> 1</span></pre>
    </div>
    <h2><a href="#静态方法"  class="anchor" id="user-content-静态方法">

    </a>静态方法
    </h2>
    <p><code>Reflect</code>对象一共有 13 个静态方法。</p>
    <ul>
        <li>Reflect.apply(target, thisArg, args)</li>
        <li>Reflect.construct(target, args)</li>
        <li>Reflect.get(target, name, receiver)</li>
        <li>Reflect.set(target, name, value, receiver)</li>
        <li>Reflect.defineProperty(target, name, desc)</li>
        <li>Reflect.deleteProperty(target, name)</li>
        <li>Reflect.has(target, name)</li>
        <li>Reflect.ownKeys(target)</li>
        <li>Reflect.isExtensible(target)</li>
        <li>Reflect.preventExtensions(target)</li>
        <li>Reflect.getOwnPropertyDescriptor(target, name)</li>
        <li>Reflect.getPrototypeOf(target)</li>
        <li>Reflect.setPrototypeOf(target, prototype)</li>
    </ul>
    <p>上面这些方法的作用，大部分与<code>Object</code>对象的同名方法的作用都是相同的，而且它与<code>Proxy</code>对象的方法是一一对应的。下面是对它们的解释。</p>
    <h3><a href="#reflectgettarget-name-receiver"  class="anchor"
           id="user-content-reflectgettarget-name-receiver">

    </a>Reflect.get(target, name, receiver)
    </h3>
    <p><code>Reflect.get</code>方法查找并返回<code>target</code>对象的<code>name</code>属性，如果没有该属性，则返回<code>undefined</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">1</span>,
  bar<span class="pl-k">:</span> <span class="pl-c1">2</span>,
  <span class="pl-k">get</span> <span class="pl-en">baz</span>() {
    <span class="pl-k">return</span> <span class="pl-c1">this</span>.<span class="pl-smi">foo</span> <span class="pl-k">+</span> <span
                class="pl-c1">this</span>.<span class="pl-smi">bar</span>;
  },
}

<span class="pl-c1">Reflect</span>.<span class="pl-c1">get</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> 1</span>
<span class="pl-c1">Reflect</span>.<span class="pl-c1">get</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>bar<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> 2</span>
<span class="pl-c1">Reflect</span>.<span class="pl-c1">get</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>baz<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> 3</span></pre>
    </div>
    <p>如果<code>name</code>属性部署了读取函数（getter），则读取函数的<code>this</code>绑定<code>receiver</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">1</span>,
  bar<span class="pl-k">:</span> <span class="pl-c1">2</span>,
  <span class="pl-k">get</span> <span class="pl-en">baz</span>() {
    <span class="pl-k">return</span> <span class="pl-c1">this</span>.<span class="pl-smi">foo</span> <span class="pl-k">+</span> <span
                class="pl-c1">this</span>.<span class="pl-smi">bar</span>;
  },
};

<span class="pl-k">var</span> myReceiverObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">4</span>,
  bar<span class="pl-k">:</span> <span class="pl-c1">4</span>,
};

<span class="pl-c1">Reflect</span>.<span class="pl-c1">get</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>baz<span class="pl-pds">'</span></span>, myReceiverObject) <span
                class="pl-c"><span class="pl-c">//</span> 8</span></pre>
    </div>
    <p>如果第一个参数不是对象，<code>Reflect.get</code>方法会报错。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">Reflect</span>.<span
            class="pl-c1">get</span>(<span class="pl-c1">1</span>, <span class="pl-s"><span
            class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>) <span class="pl-c"><span
            class="pl-c">//</span> 报错</span>
<span class="pl-c1">Reflect</span>.<span class="pl-c1">get</span>(<span class="pl-c1">false</span>, <span
                class="pl-s"><span class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>) <span
                class="pl-c"><span class="pl-c">//</span> 报错</span></pre>
    </div>
    <h3><a href="#reflectsettarget-name-value-receiver"  class="anchor"
           id="user-content-reflectsettarget-name-value-receiver">

    </a>Reflect.set(target, name, value, receiver)
    </h3>
    <p><code>Reflect.set</code>方法设置<code>target</code>对象的<code>name</code>属性等于<code>value</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">1</span>,
  <span class="pl-k">set</span> <span class="pl-en">bar</span>(<span class="pl-smi">value</span>) {
    <span class="pl-k">return</span> <span class="pl-c1">this</span>.<span class="pl-smi">foo</span> <span class="pl-k">=</span> value;
  },
}

<span class="pl-smi">myObject</span>.<span class="pl-smi">foo</span> <span class="pl-c"><span
                class="pl-c">//</span> 1</span>

<span class="pl-c1">Reflect</span>.<span class="pl-c1">set</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>, <span class="pl-c1">2</span>);
<span class="pl-smi">myObject</span>.<span class="pl-smi">foo</span> <span class="pl-c"><span
                class="pl-c">//</span> 2</span>

<span class="pl-c1">Reflect</span>.<span class="pl-c1">set</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>bar<span class="pl-pds">'</span></span>, <span class="pl-c1">3</span>)
<span class="pl-smi">myObject</span>.<span class="pl-smi">foo</span> <span class="pl-c"><span
                class="pl-c">//</span> 3</span></pre>
    </div>
    <p>如果<code>name</code>属性设置了赋值函数，则赋值函数的<code>this</code>绑定<code>receiver</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">4</span>,
  <span class="pl-k">set</span> <span class="pl-en">bar</span>(<span class="pl-smi">value</span>) {
    <span class="pl-k">return</span> <span class="pl-c1">this</span>.<span class="pl-smi">foo</span> <span class="pl-k">=</span> value;
  },
};

<span class="pl-k">var</span> myReceiverObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">0</span>,
};

<span class="pl-c1">Reflect</span>.<span class="pl-c1">set</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>bar<span class="pl-pds">'</span></span>, <span class="pl-c1">1</span>, myReceiverObject);
<span class="pl-smi">myObject</span>.<span class="pl-smi">foo</span> <span class="pl-c"><span
                class="pl-c">//</span> 4</span>
<span class="pl-smi">myReceiverObject</span>.<span class="pl-smi">foo</span> <span class="pl-c"><span
                class="pl-c">//</span> 1</span></pre>
    </div>
    <p>注意，如果 Proxy 对象和 Reflect
        对象联合使用，前者拦截赋值操作，后者完成赋值的默认行为，而且传入了<code>receiver</code>，那么<code>Reflect.set</code>会触发<code>Proxy.defineProperty</code>拦截。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">let</span> p <span class="pl-k">=</span> {
  a<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">'</span>a<span class="pl-pds">'</span></span>
};

<span class="pl-k">let</span> handler <span class="pl-k">=</span> {
  <span class="pl-en">set</span>(<span class="pl-smi">target</span>, <span class="pl-smi">key</span>, <span
                class="pl-smi">value</span>, <span class="pl-smi">receiver</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>set<span
                class="pl-pds">'</span></span>);
    <span class="pl-c1">Reflect</span>.<span class="pl-c1">set</span>(target, key, value, receiver)
  },
  <span class="pl-en">defineProperty</span>(<span class="pl-smi">target</span>, <span class="pl-smi">key</span>, <span
                class="pl-smi">attribute</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>defineProperty<span
                class="pl-pds">'</span></span>);
    <span class="pl-c1">Reflect</span>.<span class="pl-en">defineProperty</span>(target, key, attribute);
  }
};

<span class="pl-k">let</span> obj <span class="pl-k">=</span> <span class="pl-k">new</span> <span
                class="pl-en">Proxy</span>(p, handler);
<span class="pl-smi">obj</span>.<span class="pl-smi">a</span> <span class="pl-k">=</span> <span class="pl-s"><span
                class="pl-pds">'</span>A<span class="pl-pds">'</span></span>;
<span class="pl-c"><span class="pl-c">//</span> set</span>
<span class="pl-c"><span class="pl-c">//</span> defineProperty</span></pre>
    </div>
    <p>上面代码中，<code>Proxy.set</code>拦截里面使用了<code>Reflect.set</code>，而且传入了<code>receiver</code>，导致触发<code>Proxy.defineProperty</code>拦截。这是因为<code>Proxy.set</code>的<code>receiver</code>参数总是指向当前的
        Proxy 实例（即上例的<code>obj</code>），而<code>Reflect.set</code>一旦传入<code>receiver</code>，就会将属性赋值到<code>receiver</code>上面（即<code>obj</code>），导致触发<code>defineProperty</code>拦截。如果<code>Reflect.set</code>没有传入<code>receiver</code>，那么就不会触发<code>defineProperty</code>拦截。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">let</span> p <span class="pl-k">=</span> {
  a<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">'</span>a<span class="pl-pds">'</span></span>
};

<span class="pl-k">let</span> handler <span class="pl-k">=</span> {
  <span class="pl-en">set</span>(<span class="pl-smi">target</span>, <span class="pl-smi">key</span>, <span
                class="pl-smi">value</span>, <span class="pl-smi">receiver</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>set<span
                class="pl-pds">'</span></span>);
    <span class="pl-c1">Reflect</span>.<span class="pl-c1">set</span>(target, key, value)
  },
  <span class="pl-en">defineProperty</span>(<span class="pl-smi">target</span>, <span class="pl-smi">key</span>, <span
                class="pl-smi">attribute</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>defineProperty<span
                class="pl-pds">'</span></span>);
    <span class="pl-c1">Reflect</span>.<span class="pl-en">defineProperty</span>(target, key, attribute);
  }
};

<span class="pl-k">let</span> obj <span class="pl-k">=</span> <span class="pl-k">new</span> <span
                class="pl-en">Proxy</span>(p, handler);
<span class="pl-smi">obj</span>.<span class="pl-smi">a</span> <span class="pl-k">=</span> <span class="pl-s"><span
                class="pl-pds">'</span>A<span class="pl-pds">'</span></span>;
<span class="pl-c"><span class="pl-c">//</span> set</span></pre>
    </div>
    <p>如果第一个参数不是对象，<code>Reflect.set</code>会报错。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">Reflect</span>.<span
            class="pl-c1">set</span>(<span class="pl-c1">1</span>, <span class="pl-s"><span
            class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>, {}) <span class="pl-c"><span
            class="pl-c">//</span> 报错</span>
<span class="pl-c1">Reflect</span>.<span class="pl-c1">set</span>(<span class="pl-c1">false</span>, <span
                class="pl-s"><span class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>, {}) <span
                class="pl-c"><span class="pl-c">//</span> 报错</span></pre>
    </div>
    <h3><a href="#reflecthasobj-name"  class="anchor" id="user-content-reflecthasobj-name">

    </a>Reflect.has(obj, name)
    </h3>
    <p><code>Reflect.has</code>方法对应<code>name in obj</code>里面的<code>in</code>运算符。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">1</span>,
};

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-s"><span class="pl-pds">'</span>foo<span class="pl-pds">'</span></span> <span class="pl-k">in</span> myObject <span
                class="pl-c"><span class="pl-c">//</span> true</span>

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-c1">has</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>) <span class="pl-c"><span
                class="pl-c">//</span> true</span></pre>
    </div>
    <p>如果第一个参数不是对象，<code>Reflect.has</code>和<code>in</code>运算符都会报错。</p>
    <h3><a href="#reflectdeletepropertyobj-name"  class="anchor"
           id="user-content-reflectdeletepropertyobj-name">

    </a>Reflect.deleteProperty(obj, name)
    </h3>
    <p><code>Reflect.deleteProperty</code>方法等同于<code>delete obj[name]</code>，用于删除对象的属性。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">myObj</span> <span class="pl-k">=</span> { foo<span class="pl-k">:</span> <span
            class="pl-s"><span class="pl-pds">'</span>bar<span class="pl-pds">'</span></span> };

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-k">delete</span> <span class="pl-smi">myObj</span>.<span class="pl-smi">foo</span>;

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">deleteProperty</span>(myObj, <span class="pl-s"><span
                class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>);</pre>
    </div>
    <p>该方法返回一个布尔值。如果删除成功，或者被删除的属性不存在，返回<code>true</code>；删除失败，被删除的属性依然存在，返回<code>false</code>。</p>
    <h3><a href="#reflectconstructtarget-args"  class="anchor"
           id="user-content-reflectconstructtarget-args">

    </a>Reflect.construct(target, args)
    </h3>
    <p><code>Reflect.construct</code>方法等同于<code>new target(...args)</code>，这提供了一种不使用<code>new</code>，来调用构造函数的方法。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span
            class="pl-en">Greeting</span>(<span class="pl-smi">name</span>) {
  <span class="pl-c1">this</span>.<span class="pl-c1">name</span> <span class="pl-k">=</span> name;
}

<span class="pl-c"><span class="pl-c">//</span> new 的写法</span>
<span class="pl-k">const</span> <span class="pl-c1">instance</span> <span class="pl-k">=</span> <span
                class="pl-k">new</span> <span class="pl-en">Greeting</span>(<span class="pl-s"><span
                class="pl-pds">'</span>张三<span class="pl-pds">'</span></span>);

<span class="pl-c"><span class="pl-c">//</span> Reflect.construct 的写法</span>
<span class="pl-k">const</span> <span class="pl-c1">instance</span> <span class="pl-k">=</span> <span class="pl-c1">Reflect</span>.<span
                class="pl-en">construct</span>(Greeting, [<span class="pl-s"><span class="pl-pds">'</span>张三<span
                class="pl-pds">'</span></span>]);</pre>
    </div>
    <h3><a href="#reflectgetprototypeofobj"  class="anchor"
           id="user-content-reflectgetprototypeofobj">

    </a>Reflect.getPrototypeOf(obj)
    </h3>
    <p><code>Reflect.getPrototypeOf</code>方法用于读取对象的<code>__proto__</code>属性，对应<code>Object.getPrototypeOf(obj)</code>。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">myObj</span> <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">FancyThing</span>();

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-c1">Object</span>.<span class="pl-en">getPrototypeOf</span>(myObj) <span class="pl-k">===</span> <span
                class="pl-smi">FancyThing</span>.<span class="pl-c1">prototype</span>;

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">getPrototypeOf</span>(myObj) <span class="pl-k">===</span> <span
                class="pl-smi">FancyThing</span>.<span class="pl-c1">prototype</span>;</pre>
    </div>
    <p>
        <code>Reflect.getPrototypeOf</code>和<code>Object.getPrototypeOf</code>的一个区别是，如果参数不是对象，<code>Object.getPrototypeOf</code>会将这个参数转为对象，然后再运行，而<code>Reflect.getPrototypeOf</code>会报错。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">Object</span>.<span
            class="pl-en">getPrototypeOf</span>(<span class="pl-c1">1</span>) <span class="pl-c"><span
            class="pl-c">//</span> Number {[[PrimitiveValue]]: 0}</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">getPrototypeOf</span>(<span class="pl-c1">1</span>) <span
                class="pl-c"><span class="pl-c">//</span> 报错</span></pre>
    </div>
    <h3><a href="#reflectsetprototypeofobj-newproto"  class="anchor"
           id="user-content-reflectsetprototypeofobj-newproto">

    </a>Reflect.setPrototypeOf(obj, newProto)
    </h3>
    <p><code>Reflect.setPrototypeOf</code>方法用于设置对象的<code>__proto__</code>属性，返回第一个参数对象，对应<code>Object.setPrototypeOf(obj,
        newProto)</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">myObj</span> <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">FancyThing</span>();

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-c1">Object</span>.<span class="pl-en">setPrototypeOf</span>(myObj, <span
                class="pl-smi">OtherThing</span>.<span class="pl-c1">prototype</span>);

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">setPrototypeOf</span>(myObj, <span
                class="pl-smi">OtherThing</span>.<span class="pl-c1">prototype</span>);</pre>
    </div>
    <p>如果第一个参数不是对象，<code>Object.setPrototypeOf</code>会返回第一个参数本身，而<code>Reflect.setPrototypeOf</code>会报错。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">Object</span>.<span
            class="pl-en">setPrototypeOf</span>(<span class="pl-c1">1</span>, {})
<span class="pl-c"><span class="pl-c">//</span> 1</span>

<span class="pl-c1">Reflect</span>.<span class="pl-en">setPrototypeOf</span>(<span class="pl-c1">1</span>, {})
<span class="pl-c"><span class="pl-c">//</span> TypeError: Reflect.setPrototypeOf called on non-object</span></pre>
    </div>
    <p>
        如果第一个参数是<code>undefined</code>或<code>null</code>，<code>Object.setPrototypeOf</code>和<code>Reflect.setPrototypeOf</code>都会报错。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">Object</span>.<span
            class="pl-en">setPrototypeOf</span>(<span class="pl-c1">null</span>, {})
<span class="pl-c"><span class="pl-c">//</span> TypeError: Object.setPrototypeOf called on null or undefined</span>

<span class="pl-c1">Reflect</span>.<span class="pl-en">setPrototypeOf</span>(<span class="pl-c1">null</span>, {})
<span class="pl-c"><span class="pl-c">//</span> TypeError: Reflect.setPrototypeOf called on non-object</span></pre>
    </div>
    <h3><a href="#reflectapplyfunc-thisarg-args"  class="anchor"
           id="user-content-reflectapplyfunc-thisarg-args">

    </a>Reflect.apply(func, thisArg, args)
    </h3>
    <p><code>Reflect.apply</code>方法等同于<code>Function.prototype.apply.call(func, thisArg,
        args)</code>，用于绑定<code>this</code>对象后执行给定函数。</p>
    <p>一般来说，如果要绑定一个函数的<code>this</code>对象，可以这样写<code>fn.apply(obj,
        args)</code>，但是如果函数定义了自己的<code>apply</code>方法，就只能写成<code>Function.prototype.apply.call(fn, obj,
        args)</code>，采用<code>Reflect</code>对象可以简化这种操作。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">ages</span> <span class="pl-k">=</span> [<span class="pl-c1">11</span>, <span
            class="pl-c1">33</span>, <span class="pl-c1">12</span>, <span class="pl-c1">54</span>, <span class="pl-c1">18</span>, <span
            class="pl-c1">96</span>];

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-k">const</span> <span class="pl-c1">youngest</span> <span class="pl-k">=</span> <span
                class="pl-c1">Math</span>.<span class="pl-smi">min</span>.<span class="pl-c1">apply</span>(<span
                class="pl-c1">Math</span>, ages);
<span class="pl-k">const</span> <span class="pl-c1">oldest</span> <span class="pl-k">=</span> <span
                class="pl-c1">Math</span>.<span class="pl-smi">max</span>.<span class="pl-c1">apply</span>(<span
                class="pl-c1">Math</span>, ages);
<span class="pl-k">const</span> <span class="pl-c1">type</span> <span class="pl-k">=</span> <span
                class="pl-c1">Object</span>.<span class="pl-c1">prototype</span>.<span
                class="pl-smi">toString</span>.<span class="pl-c1">call</span>(youngest);

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-k">const</span> <span class="pl-c1">youngest</span> <span class="pl-k">=</span> <span class="pl-c1">Reflect</span>.<span
                class="pl-c1">apply</span>(<span class="pl-c1">Math</span>.<span class="pl-smi">min</span>, <span
                class="pl-c1">Math</span>, ages);
<span class="pl-k">const</span> <span class="pl-c1">oldest</span> <span class="pl-k">=</span> <span class="pl-c1">Reflect</span>.<span
                class="pl-c1">apply</span>(<span class="pl-c1">Math</span>.<span class="pl-smi">max</span>, <span
                class="pl-c1">Math</span>, ages);
<span class="pl-k">const</span> <span class="pl-c1">type</span> <span class="pl-k">=</span> <span
                class="pl-c1">Reflect</span>.<span class="pl-c1">apply</span>(<span class="pl-c1">Object</span>.<span
                class="pl-c1">prototype</span>.<span class="pl-smi">toString</span>, youngest, []);</pre>
    </div>
    <h3><a href="#reflectdefinepropertytarget-propertykey-attributes"  class="anchor"
           id="user-content-reflectdefinepropertytarget-propertykey-attributes">

    </a>Reflect.defineProperty(target, propertyKey, attributes)
    </h3>
    <p>
        <code>Reflect.defineProperty</code>方法基本等同于<code>Object.defineProperty</code>，用来为对象定义属性。未来，后者会被逐渐废除，请从现在开始就使用<code>Reflect.defineProperty</code>代替它。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">function</span> <span class="pl-en">MyDate</span>() {
  <span class="pl-c"><span class="pl-c">/*</span>…<span class="pl-c">*/</span></span>
}

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-c1">Object</span>.<span class="pl-en">defineProperty</span>(MyDate, <span class="pl-s"><span
                class="pl-pds">'</span>now<span class="pl-pds">'</span></span>, {
  <span class="pl-en">value</span><span class="pl-k">:</span> () <span class="pl-k">=&gt;</span> <span class="pl-c1">Date</span>.<span
                class="pl-en">now</span>()
});

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">defineProperty</span>(MyDate, <span class="pl-s"><span
                class="pl-pds">'</span>now<span class="pl-pds">'</span></span>, {
  <span class="pl-en">value</span><span class="pl-k">:</span> () <span class="pl-k">=&gt;</span> <span class="pl-c1">Date</span>.<span
                class="pl-en">now</span>()
});</pre>
    </div>
    <p>如果<code>Reflect.defineProperty</code>的第一个参数不是对象，就会抛出错误，比如<code>Reflect.defineProperty(1, 'foo')</code>。</p>
    <h3><a href="#reflectgetownpropertydescriptortarget-propertykey"  class="anchor"
           id="user-content-reflectgetownpropertydescriptortarget-propertykey">

    </a>Reflect.getOwnPropertyDescriptor(target, propertyKey)
    </h3>
    <p><code>Reflect.getOwnPropertyDescriptor</code>基本等同于<code>Object.getOwnPropertyDescriptor</code>，用于得到指定属性的描述对象，将来会替代掉后者。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {};
<span class="pl-c1">Object</span>.<span class="pl-en">defineProperty</span>(myObject, <span class="pl-s"><span
                class="pl-pds">'</span>hidden<span class="pl-pds">'</span></span>, {
  value<span class="pl-k">:</span> <span class="pl-c1">true</span>,
  enumerable<span class="pl-k">:</span> <span class="pl-c1">false</span>,
});

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-k">var</span> theDescriptor <span class="pl-k">=</span> <span class="pl-c1">Object</span>.<span
                class="pl-en">getOwnPropertyDescriptor</span>(myObject, <span class="pl-s"><span class="pl-pds">'</span>hidden<span
                class="pl-pds">'</span></span>);

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-k">var</span> theDescriptor <span class="pl-k">=</span> <span class="pl-c1">Reflect</span>.<span
                class="pl-en">getOwnPropertyDescriptor</span>(myObject, <span class="pl-s"><span class="pl-pds">'</span>hidden<span
                class="pl-pds">'</span></span>);</pre>
    </div>
    <p>
        <code>Reflect.getOwnPropertyDescriptor</code>和<code>Object.getOwnPropertyDescriptor</code>的一个区别是，如果第一个参数不是对象，<code>Object.getOwnPropertyDescriptor(1,
        'foo')</code>不报错，返回<code>undefined</code>，而<code>Reflect.getOwnPropertyDescriptor(1, 'foo')</code>会抛出错误，表示参数非法。
    </p>
    <h3><a href="#reflectisextensible-target"  class="anchor"
           id="user-content-reflectisextensible-target">

    </a>Reflect.isExtensible (target)
    </h3>
    <p><code>Reflect.isExtensible</code>方法对应<code>Object.isExtensible</code>，返回一个布尔值，表示当前对象是否可扩展。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">myObject</span> <span
            class="pl-k">=</span> {};

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-c1">Object</span>.<span class="pl-en">isExtensible</span>(myObject) <span class="pl-c"><span
                class="pl-c">//</span> true</span>

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">isExtensible</span>(myObject) <span class="pl-c"><span
                class="pl-c">//</span> true</span></pre>
    </div>
    <p>如果参数不是对象，<code>Object.isExtensible</code>会返回<code>false</code>，因为非对象本来就是不可扩展的，而<code>Reflect.isExtensible</code>会报错。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c1">Object</span>.<span
            class="pl-en">isExtensible</span>(<span class="pl-c1">1</span>) <span class="pl-c"><span
            class="pl-c">//</span> false</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">isExtensible</span>(<span class="pl-c1">1</span>) <span
                class="pl-c"><span class="pl-c">//</span> 报错</span></pre>
    </div>
    <h3><a href="#reflectpreventextensionstarget"  class="anchor"
           id="user-content-reflectpreventextensionstarget">

    </a>Reflect.preventExtensions(target)
    </h3>
    <p><code>Reflect.preventExtensions</code>对应<code>Object.preventExtensions</code>方法，用于让一个对象变为不可扩展。它返回一个布尔值，表示是否操作成功。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {};

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-c1">Object</span>.<span class="pl-en">preventExtensions</span>(myObject) <span class="pl-c"><span
                class="pl-c">//</span> Object {}</span>

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">preventExtensions</span>(myObject) <span class="pl-c"><span
                class="pl-c">//</span> true</span></pre>
    </div>
    <p>如果参数不是对象，<code>Object.preventExtensions</code>在 ES5 环境报错，在 ES6 环境返回传入的参数，而<code>Reflect.preventExtensions</code>会报错。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> ES5 环境</span>
<span class="pl-c1">Object</span>.<span class="pl-en">preventExtensions</span>(<span class="pl-c1">1</span>) <span
                class="pl-c"><span class="pl-c">//</span> 报错</span>

<span class="pl-c"><span class="pl-c">//</span> ES6 环境</span>
<span class="pl-c1">Object</span>.<span class="pl-en">preventExtensions</span>(<span class="pl-c1">1</span>) <span
                class="pl-c"><span class="pl-c">//</span> 1</span>

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">preventExtensions</span>(<span class="pl-c1">1</span>) <span
                class="pl-c"><span class="pl-c">//</span> 报错</span></pre>
    </div>
    <h3><a href="#reflectownkeys-target"  class="anchor" id="user-content-reflectownkeys-target">

    </a>Reflect.ownKeys (target)
    </h3>
    <p><code>Reflect.ownKeys</code>方法用于返回对象的所有属性，基本等同于<code>Object.getOwnPropertyNames</code>与<code>Object.getOwnPropertySymbols</code>之和。
    </p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> myObject <span class="pl-k">=</span> {
  foo<span class="pl-k">:</span> <span class="pl-c1">1</span>,
  bar<span class="pl-k">:</span> <span class="pl-c1">2</span>,
  [<span class="pl-c1">Symbol</span>.<span class="pl-en">for</span>(<span class="pl-s"><span
                class="pl-pds">'</span>baz<span class="pl-pds">'</span></span>)]<span class="pl-k">:</span> <span
                class="pl-c1">3</span>,
  [<span class="pl-c1">Symbol</span>.<span class="pl-en">for</span>(<span class="pl-s"><span class="pl-pds">'</span>bing<span
                class="pl-pds">'</span></span>)]<span class="pl-k">:</span> <span class="pl-c1">4</span>,
};

<span class="pl-c"><span class="pl-c">//</span> 旧写法</span>
<span class="pl-c1">Object</span>.<span class="pl-en">getOwnPropertyNames</span>(myObject)
<span class="pl-c"><span class="pl-c">//</span> ['foo', 'bar']</span>

<span class="pl-c1">Object</span>.<span class="pl-en">getOwnPropertySymbols</span>(myObject)
<span class="pl-c"><span class="pl-c">//</span>[Symbol(baz), Symbol(bing)]</span>

<span class="pl-c"><span class="pl-c">//</span> 新写法</span>
<span class="pl-c1">Reflect</span>.<span class="pl-en">ownKeys</span>(myObject)
<span class="pl-c"><span class="pl-c">//</span> ['foo', 'bar', Symbol(baz), Symbol(bing)]</span></pre>
    </div>
    <h2><a href="#实例使用-proxy-实现观察者模式"  class="anchor" id="user-content-实例使用-proxy-实现观察者模式">

    </a>实例：使用 Proxy 实现观察者模式
    </h2>
    <p>观察者模式（Observer mode）指的是函数自动观察数据对象，一旦对象有变化，函数就会自动执行。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">person</span> <span class="pl-k">=</span> <span class="pl-en">observable</span>({
  name<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">'</span>张三<span class="pl-pds">'</span></span>,
  age<span class="pl-k">:</span> <span class="pl-c1">20</span>
});

<span class="pl-k">function</span> <span class="pl-en">print</span>() {
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span
                class="pl-pds">`</span><span class="pl-s1"><span class="pl-pse">${</span><span
                class="pl-smi">person</span>.<span class="pl-c1">name</span><span class="pl-pse">}</span></span>, <span
                class="pl-s1"><span class="pl-pse">${</span><span class="pl-smi">person</span>.<span
                class="pl-smi">age</span><span class="pl-pse">}</span></span><span class="pl-pds">`</span></span>)
}

<span class="pl-en">observe</span>(print);
<span class="pl-smi">person</span>.<span class="pl-c1">name</span> <span class="pl-k">=</span> <span class="pl-s"><span
                class="pl-pds">'</span>李四<span class="pl-pds">'</span></span>;
<span class="pl-c"><span class="pl-c">//</span> 输出</span>
<span class="pl-c"><span class="pl-c">//</span> 李四, 20</span></pre>
    </div>
    <p>上面代码中，数据对象<code>person</code>是观察目标，函数<code>print</code>是观察者。一旦数据对象发生变化，<code>print</code>就会自动执行。</p>
    <p>下面，使用 Proxy 写一个观察者模式的最简单实现，即实现<code>observable</code>和<code>observe</code>这两个函数。思路是<code>observable</code>函数返回一个原始对象的
        Proxy 代理，拦截赋值操作，触发充当观察者的各个函数。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span
            class="pl-c1">queuedObservers</span> <span class="pl-k">=</span> <span class="pl-k">new</span> <span
            class="pl-en">Set</span>();

<span class="pl-k">const</span> <span class="pl-c1">observe</span> <span class="pl-k">=</span> <span
                class="pl-smi">fn</span> <span class="pl-k">=&gt;</span> <span
                class="pl-smi">queuedObservers</span>.<span class="pl-c1">add</span>(fn);
<span class="pl-k">const</span> <span class="pl-c1">observable</span> <span class="pl-k">=</span> <span class="pl-smi">obj</span> <span
                class="pl-k">=&gt;</span> <span class="pl-k">new</span> <span class="pl-en">Proxy</span>(obj, {set});

<span class="pl-k">function</span> <span class="pl-en">set</span>(<span class="pl-smi">target</span>, <span
                class="pl-smi">key</span>, <span class="pl-smi">value</span>, <span class="pl-smi">receiver</span>) {
  <span class="pl-k">const</span> <span class="pl-c1">result</span> <span class="pl-k">=</span> <span class="pl-c1">Reflect</span>.<span
                class="pl-c1">set</span>(target, key, value, receiver);
  <span class="pl-smi">queuedObservers</span>.<span class="pl-c1">forEach</span>(<span
                class="pl-smi">observer</span> <span class="pl-k">=&gt;</span> <span class="pl-en">observer</span>());
  <span class="pl-k">return</span> result;
}</pre>
    </div>
    <p>上面代码中，先定义了一个<code>Set</code>集合，所有观察者函数都放进这个集合。然后，<code>observable</code>函数返回原始对象的代理，拦截赋值操作。拦截函数<code>set</code>之中，会自动执行所有观察者。
    </p>
</div>
</body>
</html>
